namespace Fadd.Data
{
    /// <summary>
    /// Query statement
    /// </summary>
    public class Statement
    {
        private readonly object[] _arguments;
        private readonly string _conditions;
        private string[] _orderBy;
        private string[] _groupBy;
        private int _page;
        private int _pageSize;

        /// <summary>
        /// Initializes a new instance of the <see cref="Statement"/> class.
        /// </summary>
        /// <param name="conditions">Conditions (corresponds to the WHERE clause) using property names.</param>
        /// <param name="arguments">Argument values used in the condition.</param>
        public Statement(string conditions, params object[] arguments)
        {
            _conditions = conditions;
            _arguments = arguments;
        }


        /// <summary>
        /// Initializes a new instance of the <see cref="Statement"/> class.
        /// </summary>
        public Statement()
        {
        }

        /// <summary>
        /// Arguments being used in <see cref="Statement"/>.
        /// </summary>
        public object[] Arguments
        {
            get { return _arguments; }
        }

        /// <summary>
        /// Conditions (corresponds to the WHERE clause) using property names
        /// </summary>
        public string Conditions
        {
            get { return _conditions; }
        }

        /// <summary>
        /// Property names + ASC/DESC
        /// </summary>
        public string[] OrderByClause
        {
            get { return _orderBy; }
        }

        /// <summary>
        /// Property names to group by
        /// </summary>
        public string[] GroupByClause
        {
            get { return _groupBy; }
            set { _groupBy = value; }
        }

        /// <summary>
        /// 0 based index. 0 = first page, 1 = second page..
        /// </summary>
        public int Page
        {
            get { return _page; }
        }

        /// <summary>
        /// Number of entries per page
        /// </summary>
        public int PageSize
        {
            get { return _pageSize; }
        }

        /// <summary>
        /// Properties to sort by. 
        /// </summary>
        /// <param name="properties">properties separated by comma, with or without ASC/DESC.</param>
        /// <returns>the current statement</returns>
        /// <example>new Statement("FirstName = ?", firstName).OrderBy("LastName DESC, FirstName")</example>
        public Statement OrderBy(params string[] properties)
        {
            if (properties == null)
                return this;
            if (properties.Length == 1 && string.IsNullOrEmpty(properties[0]))
                return this;

            _orderBy = properties;
            return this;
        }

        /// <summary>
        /// Properties to group the statement by
        /// </summary>
        /// <param name="properties">Properties to group by, separated by comma.</param>
        /// <returns></returns>
        /// <example>new Statement(string.Empty).GroupBy("LastName, FirstName")</example>
        public Statement GroupBy(params string[] properties)
        {
            if (properties == null)
                return this;
            if (properties.Length == 1 && string.IsNullOrEmpty(properties[0]))
                return this;
            
            _groupBy = properties;
            return this;
        }

        /// <summary>
        /// Get a certain amount of entries.
        /// </summary>
        /// <param name="page">0 based index. 0 = first page, 1 = second page..</param>
        /// <param name="itemsPerPage">Number of entries per page.</param>
        /// <returns></returns>
        public Statement Paging(int page, int itemsPerPage)
        {
            _page = page;
            _pageSize = itemsPerPage;
            return this;
        }

        /// <summary>
        /// Calculates hash code by concatenating the strings for all statement parts.
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            string entries = string.Empty;

            if (_conditions != null)
                entries += _conditions;
            entries += '|';

            if (_groupBy != null)
                foreach (string s in _groupBy)
                    entries += s;
            entries += '|';

            if (_orderBy != null)
                foreach (string s in _orderBy)
                    entries += s;

            return entries.GetHashCode();
        }
    }
}
